package com.pan.kang.frame.domain;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.sql.DataSource;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

@Component
public class ProcedureExecutor implements IProcedureExecutor {

    @Autowired
    private DataSource dataSource;

    @Override
    public Map<String, ?> executeProcedure(String procedureName, Map<String, Object> mapIn,
                                           Map<String, Object> mapOut) {
        try {
            Map<String, Object> resultMap = new HashMap<String, Object>();
            Connection connection = dataSource.getConnection();
            int inSize = 0;
            int outSize = 0;
            boolean hasIn = !CollectionUtils.isEmpty(mapIn);
            boolean hasOut = !CollectionUtils.isEmpty(mapOut);
            if (hasIn) {
                inSize = mapIn.size();
            }
            if (hasOut) {
                outSize = mapOut.size();
            }
            int paramSize = inSize + outSize;
            CallableStatement statement = connection.prepareCall(getProcedureSQL(procedureName, paramSize));
            if (hasIn) {
                mapIn.forEach((k, v) -> {
                    try {
                        statement.setObject(k, v);
                    } catch (SQLException e) {
                        throw new RuntimeException(e);
                    }
                });
            }
            if (hasOut) {
                mapOut.forEach((k, v) -> {
                    try {
                        statement.registerOutParameter(k, Integer.parseInt(v.toString()));
                    } catch (SQLException e) {
                        throw new RuntimeException(e);
                    }
                });
            }
            statement.execute();
            if (hasOut) {
                mapOut.keySet().forEach(k -> {
                    try {
                        Object obj = statement.getObject(k);
                        resultMap.put(k, obj);
                    } catch (SQLException e) {
                        throw new RuntimeException(e);
                    }
                });

            }
            return resultMap;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static String getProcedureSQL(String procedureName, int paramSize) {
        StringBuilder sb = new StringBuilder("{call ");
        sb.append(procedureName).append("(");
        for (int i = 0; i < paramSize; ++i) {
            sb.append("?,");
        }
        if (paramSize > 0) {
            sb.deleteCharAt(sb.length() - 1);
        }
        return sb.append(")}").toString();
    }
}
